# Refresh Token 服务

import uuid
from datetime import datetime, timedelta, timezone
from typing import Optional, Dict, Any
from src.cores.redis import redis_manager
from src.utils.jwt_auth import jwt_auth
from src.utils.logger import app_logger as logger


class RefreshTokenService:
    """Refresh Token 服务类"""
    
    # Redis key 前缀
    REFRESH_TOKEN_PREFIX = "refresh_token:"
    USER_REFRESH_TOKENS_PREFIX = "user_refresh_tokens:"
    
    @staticmethod
    async def create_token_pair(
        user_id: int, 
        username: str, 
        device_id: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        创建access token和refresh token对
        
        Args:
            user_id: 用户ID
            username: 用户名
            device_id: 设备ID（可选，用于多设备管理）
            
        Returns:
            Dict[str, Any]: 包含token信息的字典
        """
        try:
            # 生成唯一的refresh token ID
            refresh_token_id = str(uuid.uuid4())
            
            # 创建token对
            tokens = jwt_auth.create_token_pair(
                user_id=user_id,
                username=username,
                extra_data={"refresh_token_id": refresh_token_id}
            )
            
            # 在Redis中存储refresh token信息
            refresh_token_data = {
                "user_id": user_id,
                "username": username,
                "device_id": device_id or "unknown",
                "created_at": datetime.now(timezone.utc).isoformat(),
                "is_active": True
            }
            
            # 存储refresh token信息（30天过期）
            import json
            await redis_manager.set(
                f"{RefreshTokenService.REFRESH_TOKEN_PREFIX}{refresh_token_id}",
                json.dumps(refresh_token_data),
                ex=30 * 24 * 3600  # 30天
            )
            
            # 将refresh token ID添加到用户的token列表中
            user_tokens_key = f"{RefreshTokenService.USER_REFRESH_TOKENS_PREFIX}{user_id}"
            await redis_manager.sadd(user_tokens_key, refresh_token_id)
            await redis_manager.expire(user_tokens_key, 30 * 24 * 3600)  # 30天过期
            
            # 获取access token过期时间
            from src.config.settings import get_settings
            settings = get_settings()
            expires_in = settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
            
            logger.info(f"为用户 {username}({user_id}) 创建了新的token对")
            
            return {
                "access_token": tokens["access_token"],
                "refresh_token": tokens["refresh_token"],
                "token_type": "Bearer",
                "expires_in": expires_in,
                "refresh_token_id": refresh_token_id
            }
            
        except Exception as e:
            logger.error(f"创建token对失败: {str(e)}")
            raise
    
    @staticmethod
    async def refresh_access_token(refresh_token: str) -> Optional[Dict[str, Any]]:
        """
        使用refresh token刷新access token
        
        Args:
            refresh_token: 刷新令牌
            
        Returns:
            Optional[Dict[str, Any]]: 新的access token信息，如果失败返回None
        """
        try:
            # 验证refresh token
            payload = jwt_auth.verify_token(refresh_token)
            if not payload or payload.get("type") != "refresh_token":
                logger.warning("无效的refresh token")
                return None
            
            user_id = payload.get("user_id")
            username = payload.get("username")
            refresh_token_id = payload.get("refresh_token_id")
            
            if not all([user_id, username, refresh_token_id]):
                logger.warning("refresh token缺少必要信息")
                return None
            
            # 检查refresh token是否在Redis中存在且有效
            token_data_str = await redis_manager.get(
                f"{RefreshTokenService.REFRESH_TOKEN_PREFIX}{refresh_token_id}"
            )
            
            if not token_data_str:
                logger.warning(f"refresh token {refresh_token_id} 不存在或已过期")
                return None
                
            import json
            token_data = json.loads(token_data_str)
            
            if not token_data.get("is_active"):
                logger.warning(f"refresh token {refresh_token_id} 不存在或已失效")
                return None
            
            # 验证用户信息是否匹配
            if (
                token_data.get("user_id") != user_id or 
                token_data.get("username") != username
            ):
                logger.warning(f"refresh token用户信息不匹配")
                return None
            
            # 生成新的access token
            new_access_token = jwt_auth.create_access_token(
                user_id=user_id,
                username=username,
                extra_data={"refresh_token_id": refresh_token_id}
            )
            
            # 获取access token过期时间
            from src.config.settings import get_settings
            settings = get_settings()
            expires_in = settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60
            
            logger.info(f"为用户 {username}({user_id}) 刷新了access token")
            
            return {
                "access_token": new_access_token,
                "token_type": "Bearer",
                "expires_in": expires_in
            }
            
        except Exception as e:
            logger.error(f"刷新access token失败: {str(e)}")
            return None
    
    @staticmethod
    async def revoke_refresh_token(refresh_token: str) -> bool:
        """
        撤销refresh token
        
        Args:
            refresh_token: 要撤销的刷新令牌
            
        Returns:
            bool: 撤销是否成功
        """
        try:
            # 验证refresh token
            payload = jwt_auth.verify_token(refresh_token)
            if not payload or payload.get("type") != "refresh_token":
                return False
            
            refresh_token_id = payload.get("refresh_token_id")
            user_id = payload.get("user_id")
            
            if not refresh_token_id:
                return False
            
            # 从Redis中删除refresh token
            await redis_manager.delete(
                f"{RefreshTokenService.REFRESH_TOKEN_PREFIX}{refresh_token_id}"
            )
            
            # 从用户token列表中移除
            if user_id:
                await redis_manager.srem(
                    f"{RefreshTokenService.USER_REFRESH_TOKENS_PREFIX}{user_id}",
                    refresh_token_id
                )
            
            logger.info(f"撤销了refresh token: {refresh_token_id}")
            return True
            
        except Exception as e:
            logger.error(f"撤销refresh token失败: {str(e)}")
            return False
    
    @staticmethod
    async def revoke_all_user_tokens(user_id: int) -> bool:
        """
        撤销用户的所有refresh token
        
        Args:
            user_id: 用户ID
            
        Returns:
            bool: 撤销是否成功
        """
        try:
            user_tokens_key = f"{RefreshTokenService.USER_REFRESH_TOKENS_PREFIX}{user_id}"
            
            # 获取用户所有的refresh token ID
            token_ids = await redis_manager.smembers(user_tokens_key)
            
            if token_ids:
                # 删除所有refresh token
                for token_id in token_ids:
                    await redis_manager.delete(
                        f"{RefreshTokenService.REFRESH_TOKEN_PREFIX}{token_id}"
                    )
                
                # 清空用户token列表
                await redis_manager.delete(user_tokens_key)
                
                logger.info(f"撤销了用户 {user_id} 的所有refresh token，共 {len(token_ids)} 个")
            
            return True
            
        except Exception as e:
            logger.error(f"撤销用户所有refresh token失败: {str(e)}")
            return False
    
    @staticmethod
    async def get_user_active_tokens(user_id: int) -> list:
        """
        获取用户的活跃refresh token列表
        
        Args:
            user_id: 用户ID
            
        Returns:
            list: 活跃的refresh token信息列表
        """
        try:
            user_tokens_key = f"{RefreshTokenService.USER_REFRESH_TOKENS_PREFIX}{user_id}"
            token_ids = await redis_manager.smembers(user_tokens_key)
            
            active_tokens = []
            for token_id in token_ids:
                token_data_str = await redis_manager.get(
                    f"{RefreshTokenService.REFRESH_TOKEN_PREFIX}{token_id}"
                )
                if token_data_str:
                    import json
                    token_data = json.loads(token_data_str)
                    if token_data.get("is_active"):
                        active_tokens.append({
                            "token_id": token_id,
                            "device_id": token_data.get("device_id"),
                            "created_at": token_data.get("created_at")
                        })
            
            return active_tokens
            
        except Exception as e:
            logger.error(f"获取用户活跃token失败: {str(e)}")
            return []